﻿using System.Collections.Generic;

using Zeta;
using Zeta.Common;
using Zeta.CommonBot;
using Zeta.Internals.Actors;
using Zeta.TreeSharp;

namespace Belphegor.Composites
{
    public class SpellCast : Composite
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="SpellCast"/> class.
        /// </summary>
        /// <param name="power">The power.</param>
        /// <param name="posRetriever">The pos retriever.</param>
        /// <param name="dynWorldRetriever">The dyn world retriever.</param>
        /// <param name="targetRetriever">The target retriever.</param>
        /// <param name="extra">The extra.</param>
        /// <remarks>Created 2012-06-18</remarks>
        public SpellCast(SNOPower power, ValueRetriever<Vector3> posRetriever = null, ValueRetriever<int> dynWorldRetriever = null, ValueRetriever<int> targetRetriever = null, ValueRetriever<bool> extra = null)
        {
            Power = power;
            PositionRetriever = posRetriever;
            DynamicWorldIdRetriever = dynWorldRetriever;
            TargetGuidRetriever = targetRetriever;
            ExtraCondition = extra;
        }

        private SNOPower Power { get; set; }

        private ValueRetriever<Vector3> PositionRetriever { get; set; }

        private ValueRetriever<int> DynamicWorldIdRetriever { get; set; }

        private ValueRetriever<int> TargetGuidRetriever { get; set; }

        private ValueRetriever<bool> ExtraCondition { get; set; } 

        #region Overrides of Composite

        protected override IEnumerable<RunStatus> Execute(object context)
        {
            bool canCast = PowerManager.CanCast(Power);
            bool minReqs = ExtraCondition != null ? ExtraCondition(context) : true;

            if (!minReqs || !canCast)
            {
                yield return RunStatus.Failure;
            }

            Vector3 position = PositionRetriever != null ? PositionRetriever(context) : Vector3.Zero;
            int levelArea = DynamicWorldIdRetriever != null ? DynamicWorldIdRetriever(context) : 0;
            int acdGuid = TargetGuidRetriever != null ? TargetGuidRetriever(context) : -1;

            ZetaDia.Me.UsePower(Power, position, levelArea, acdGuid != -1 ? 1 : 2, acdGuid);
            Logging.WriteVerbose("Using power: {0}", Power.ToString());
            
            yield return RunStatus.Success;
        }

        #endregion
    }

    public class SelfCast : SpellCast
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="SelfCast"/> class.
        /// </summary>
        /// <param name="power">The power.</param>
        /// <param name="extra">The extra.</param>
        /// <remarks>Created 2012-06-18</remarks>
        public SelfCast(SNOPower power, ValueRetriever<bool> extra = null)
            : base(power, null, ctx => ZetaDia.CurrentWorldDynamicId, null, extra)
        {
        }
    }

    public class CastOnUnit : SpellCast
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="CastOnUnit"/> class.
        /// </summary>
        /// <param name="power">The power.</param>
        /// <param name="targetRetriever">The target retriever.</param>
        /// <param name="extra">The extra.</param>
        /// <remarks>Created 2012-06-18</remarks>
        public CastOnUnit(SNOPower power, ValueRetriever<int> targetRetriever, ValueRetriever<bool> extra = null) 
            : base(power, null, null, targetRetriever, extra)
        {
        }
    }

    public class CastAtLocation : SpellCast
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="SpellCast"/> class.
        /// </summary>
        /// <param name="power">The power.</param>
        /// <param name="posRetriever">The pos retriever.</param>
        /// <param name="extra">The extra.</param>
        /// <remarks>Created 2012-06-18</remarks>
        public CastAtLocation(SNOPower power, ValueRetriever<Vector3> posRetriever, ValueRetriever<bool> extra = null)
            : base(power, posRetriever, ctx => ZetaDia.CurrentWorldDynamicId, null, extra)
        {
        }
    }
}
